﻿using Microsoft.Extensions.DependencyInjection;
using Modules.System.Role;
using Modules.System.User;
using PetaPoco;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Caching;
using PmSoft.DBContext;
using PmSoft.Entity;
using PmSoft.Repositories;
using PmSoft.Utilities;

namespace Modules.Reports;

/// <summary>
/// 项目月统计报表仓储
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class ReportProjectMonthRepository : Repository<ReportProjectMonth, DefaultDbContext>
{
    private readonly IApplicationContext applicationContext;
    public ReportProjectMonthRepository(DefaultDbContext dbContext, IApplicationContext applicationContext) : base(dbContext, applicationContext)
    {
        this.applicationContext = applicationContext;
    }

    /// <summary>
    /// 更新或创建
    /// </summary>
    /// <param name="entity"></param>
    public void CreateOrUpdate(ReportProjectMonth entity)
    {
        Sql sql = Sql.Builder
             .Select("id")
             .From("report_project_month")
             .Where("project_id=@0 AND month=@1", entity.ProjectId, entity.Month);
        var id = DbContext.FirstOrDefault<int>(sql);
        if (id > 0)
        {
            entity.Id = id;
            base.Update(entity);
        }
        else
            base.Insert(entity);
    }


    /// <summary>
    ///  获取指定月份和代发落实状态的项目
    ///  由于查询数据可能较多，不走缓存，高频读取不要用次方法
    /// </summary>
    /// <param name="month"></param>
    /// <returns></returns>
    public IEnumerable<ReportProjectMonth> GetReportProjectsMonthsInWageStatus(int month, IEnumerable<落实状态> wageStatus)
    {
        if (wageStatus.Count() == 0)
            return Enumerable.Empty<ReportProjectMonth>();

        Sql sql = Sql.Builder
           .Select("*")
           .From("report_project_month")
           .Where("month=@0 AND wageStatus IN(@1)", month, wageStatus);

        return DbContext.Fetch<ReportProjectMonth>(sql);
    }


    /// <summary>
    /// 查没有今日没有更新的项目月报表的项目ID集合
    /// </summary>
    /// <param name="month"></param>
    /// <param name="limit"></param>
    /// <returns></returns>
    public IEnumerable<int> GetProjectIdsInNoUpdate(int month, int limit = 100)
    {
        Sql sql = Sql.Builder
           .Select("a.project_id")
           .From("project AS a")
           .Where("a.is_deleted=0 AND NOT EXISTS (SELECT  b.project_id FROM report_project_month AS b WHERE b.project_id=a.project_id AND b.month=@0 AND DATEDIFF(b.update_time,@1)=0)", month, DateTime.Now)
           .Append($"LIMIT {limit}");
        return DbContext.FetchFirstColumn<int>(sql);
    }

    /// <summary>
    /// 获取指定项目指定月数据 
    /// 这个方法注释掉 by pingmac
    /// </summary>
    /// <param name="month">ToShortDateString()</param>
    /// <param name="projectId"></param>
    /// <returns></returns>
    //public IEnumerable<ReportProjectMonth> GetReportProjectMonthByProjectIds(IEnumerable<int> projectIds)
    //{
    //    if (projectIds == null || projectIds.Count() == 0)
    //        return Enumerable.Empty<ReportProjectMonth>();
    //    Sql sql = Sql.Builder
    //       .Select("id")
    //       .From("report_project_month")
    //       .Where("project_id in(@0)", projectIds);
    //    var ids = DbContext.FetchFirstColumn<int>(sql);
    //    return PopulateEntitiesByEntityIds(ids);
    //}

    /// <summary>
    /// 获取指定项目ID所有月报表
    /// </summary>
    /// <param name="projectId"></param>
    /// <returns></returns>
    public IEnumerable<ReportProjectMonth> GetReportProjectMonthByProjectId(int projectId)
    {
        //一个项目下有限的月报表数据可以采用这种区域缓存
        int areaVersion = EntityCacheService.GetAreaVersion("ProjectId", projectId);
        return GetTopEntities(1000, CachingExpirationType.ObjectCollection, () =>
        {
            return $"ReportProjectMonthByProjectId:{projectId}:{areaVersion}";
        }, () =>
        {

            return Sql.Builder
                  .Select("id")
                  .From("report_project_month")
                  .Where("project_id=@0", projectId);
        });
    }

    /// <summary>
    /// 月报表分页
    /// </summary>
    /// <param name="query"></param>
    /// <param name="pageIndex"></param>
    /// <param name="pageSize"></param>
    /// <returns></returns>
    public IPagedList<ReportProjectMonth> GetReportProjectMonths(ReportProjectMonthQuery query, int pageIndex, int pageSize)
    {
        Sql sql = Sql.Builder;
        sql.Select("report_project_month.id")
            .From("report_project_month ");
        sql.InnerJoin("project as b").On("report_project_month.project_id=b.project_id");
        #region 主管单位数据权限
        if (applicationContext.CurrentUser is IDeptUser deptUser && !deptUser.IsSuperAdministrator())
        {
            sql.InnerJoin("project as prj").On($"report_project_month.project_id=prj.project_id and prj.is_deleted=0 and prj.industry_type=@0 ", deptUser.IndustryType);
            if (deptUser.Level == AdministrativeLevel.City)
                sql.Append($" and prj.city_code={deptUser.CityCode}");
            if (deptUser.Level == AdministrativeLevel.Area)
                sql.Append($" and prj.area_code={deptUser.AreaCode}");
        }
        #endregion
        if (query.ProjectId.HasValue)
            sql.Where("report_project_month.project_id=@0", query.ProjectId);
        if (!string.IsNullOrEmpty(query.Keywords))
            sql.Where("(b.name Like @0 or b.code Like @0)", "%" + StringUtility.StripSQLInjection(query.Keywords) + "%");
        if (!string.IsNullOrEmpty(query.AreaCode))
            sql.Where("(b.city_code=@0 or b.area_code = @0)", query.AreaCode);
        sql.Where("month = @0", query.Month);
        sql.OrderBy("report_project_month.create_time DESC");
        return GetPagingEntities(pageSize, pageIndex, sql);
    }
}